package edu.hawaii.myisern.action;

import java.text.DateFormat;
import java.text.Format;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import edu.hawaii.myisern.collaborations.jaxb.Collaboration;
import edu.hawaii.myisern.model.MyIsernModel;
import edu.hawaii.myisern.organizations.jaxb.Organization;
import edu.hawaii.myisern.researchers.jaxb.Researcher;
import edu.hawaii.myisern.sanitycheck.SanityCheckErrorItem;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.StreamingResolution;

import java.io.StringReader;

/**
 * Provides a web interface for pushing and popping a Stack instance.
 * 
 * @author Philip Johnson
 */
public class MyIsernActionBean implements ActionBean {
  
  
  /** Required by the ActionBean interface. */
  private ActionBeanContext context;
  /** Our single MyIsern instance manipulated by all webapp users. */
  private MyIsernModel myIsernModel = MyIsernModel.getInstance();
  private String nameEmpty = "Name field cannot be empty!";
  private String text = "text";
  //private String login = "";
  private String username = "";
  private String password = "";
  private String researcherName;
  private String researcherOrganization = "";
  private String email = "";
  private String pictureLink = "";
  private String bioStatement = "";
  private String organizationName = "";
  private String organizationType = "";
  private String contact = "";
  private String affiliatedResearcher = "";
  private String country = "";
  private String researchKeywords = "";
  private String researchDescription = "";
  private String homePage = "";

  private String collaborationName = "";
  private String collaboratingOrganizations = "";
  private String collaborationTypes = "";
  
  private String year = "";
  private String outcomeTypes = "";
  private String description = "";

  private List<Organization> organizations;
  private List<Researcher> researchers;
  private List<Collaboration> collaborations;
  
  private String findId = "";
  //private String mainPage = "/mainPage.jsp";
  
  private boolean checkResearchers = true;
  private boolean checkOrganizations = true;
  private boolean checkCollaborations = true;
  private String filter = "all";

  /** An error string, always displayed, but invisible if empty. */
  private String errorMessage = "";
  /** Researcher object to be edited. */
  private Researcher editResearcher;
  
  /**
   * Returns the context required by the interface.
   * 
   * @return the ActionBeanContext.
   */
  public ActionBeanContext getContext() {
    return this.context;
  }

  /**
   * Sets the context. Required by the interface. 
   * @param context The ActionBeanContext to set. 
   */
  public void setContext(ActionBeanContext context) {
    this.context = context;
  }
  
 /**
   * Provides the username string.
   * @return login The login string
   */
  public String getUsername() {
    return this.username;
  }
  
  /** 
   * Sets the login string.
   * @param username  The new login string
   */
  public void setUsername(String username) {
    this.username = username;
  }

  /**
   * A handler that performs the action when the 'login' button is pressed.
   * 
   * @return A Resolution indicating to redisplay the index.jsp page.
   */
  public Resolution login() {
    if (myIsernModel.getUserManager().authenticate(this.username, this.password)) {
        return new ForwardResolution("/mainPage.jsp");
    }
    else {
      this.username = "";
      this.password = "";
      this.errorMessage = "Invalid username/password";
      return getContext().getSourcePageResolution();
    }
   }

  /**
   * A handler that performs the action when the 'save' button is pressed.
   * Saves the new Collaboration.
   * @return A Resolution indicating to redisplay the mainPage.jsp page.
   * @throws Exception  If an error occurs
   */
  public Resolution saveCollaboration() throws Exception {
    boolean isValid = true;
    if (this.getCollaborationName() == null) {
      this.errorMessage = nameEmpty;
      isValid = false;
    }
    else if (this.getCollaboratingOrganizations() == null) {
      this.errorMessage = "collaborating-Organizations field cannot be empty!";
      isValid = false;
    }
    else if (this.getCollaborationTypes() == null) {
      this.errorMessage = "Collaboration-Types field cannot be empty!";
      isValid = false;
    }
    else if (this.getYear() == null) {
      this.errorMessage = "Year field cannot be empty!";
      isValid = false;
    }
    else if (this.getOutcomeTypes() == null) {
      this.errorMessage = "Outcome-Types field cannot be empty!";
      isValid = false;
    }
    if (isValid) {
      myIsernModel.saveCollaboration(getCollaborationName(),
        getCollaboratingOrganizations(), getCollaborationTypes(), getYear(),
        getOutcomeTypes(), getDescription());
      String success = "";
      return new StreamingResolution("text", new StringReader(success));
    }
    else {
      String error = this.errorMessage;
      return new StreamingResolution(text, new StringReader(error));
    }
  }

  /**
   * Provides the Collaboration name.
   * 
   * @return Collaboration name.
   */
  public String getCollaborationName() {
    return this.collaborationName;
  }

  /**
   * Provides the collaborating organizations.
   * 
   * @return collaborating organizations.
   */
  public String getCollaboratingOrganizations() {
    return this.collaboratingOrganizations;
  }

  /**
   * Provides the Collaborating types.
   * 
   * @return Collaborating types.
   */
  public String getCollaborationTypes() {
    return this.collaborationTypes;
  }

  /**
   * Provides the Collaboration years.
   * 
   * @return Collaborating years.
   */
  public String getYear() {
    return this.year;
  }

  /**
   * Provides the Collaborating outcome types.
   * 
   * @return Collaborating Outcome-Types.
   */
  public String getOutcomeTypes() {
    return this.outcomeTypes;
  }

  /**
   * Provides the Collaboration description.
   * 
   * @return Collaboration description. 
   */
  public String getDescription() {
    return this.description;
  }

  /**
   * Sets the collaboration name.
   * 
   * @param collaborationName  The new collaboration name
   */
  public void setCollaborationName(String collaborationName) {
    this.collaborationName = collaborationName;
  }

  /**
   * Sets the Collaborating organizations.
   * 
   * @param collaboratingOrganizations  The new collaborating organization
   */
  public void setCollaboratingOrganizations(String collaboratingOrganizations) {
    this.collaboratingOrganizations = collaboratingOrganizations;
  }

  /**
   * Sets the Collaboration types.
   * 
   * @param collaborationTypes The new collaboration types
   */
  public void setCollaborationTypes(String collaborationTypes) {
    this.collaborationTypes = collaborationTypes;
  }

  /**
   * Sets the Collaboration years.
   * 
   * @param year The new year
   */
  public void setYear(String year) {
    this.year = year;
  }

  /**
   * Sets the collaborating outcome types.
   * 
   * @param outcomeTypes The new out-come types
   */
  public void setOutcomeTypes(String outcomeTypes) {
    this.outcomeTypes = outcomeTypes;
  }

  /**
   * Sets the collaboration description.
   * 
   * @param description The new description
   */
  public void setDescription(String description) {
    this.description = description;
  }

  /**
   * A handler that performs the action when the 'save' button is pressed.
   * Saves the new Organization.
   * @return A Resolution indicating to redisplay the mainPage.jsp page.
   * @throws Exception If an error occurs.
   */
  public Resolution saveOrganization() throws Exception {
    boolean isValid = true;
    if (this.getOrganizationName() == null) {
      this.errorMessage = nameEmpty;
      isValid = false;
    }
    else if (this.getContact() == null) {
      this.errorMessage = "Contact field cannot be empty!";
      isValid = false;
    }
    else if (this.getAffiliatedResearcher() == null) {
      this.errorMessage = "Affiliated-Researcher field cannot be empty!";
      isValid = false;
    }
    else if (this.getResearchKeywords() == null) {
      this.errorMessage = "Research-Keywords field cannot be empty!";
      isValid = false;
    }
    if (isValid) {
      myIsernModel.saveOrganization(this.getOrganizationName(), this
        .getOrganizationType(), this.getContact(), this
        .getAffiliatedResearcher(), this.getCountry(), this
        .getResearchKeywords(), this.getResearchDescription(), this
        .getHomePage());
      String success = "";
      return new StreamingResolution(text, new StringReader(success));
    }
    else {
      String error = this.errorMessage;
      return new StreamingResolution(text, new StringReader(error));
    }
  }

  /**
   * Provides the Organization name.
   * 
   * @return Organization's name.
   */
  public String getOrganizationName() {
    return this.organizationName;
  }

  /**
   * Provides the Organization type.
   * 
   * @return Organization type.
   */
  public String getOrganizationType() {
    return this.organizationType;
  }

  /**
   * Provides the Organization contact.
   * 
   * @return Organization contact.
   */
  public String getContact() {
    return this.contact;
  }

  /**
   * Provides the Organization's affiliated researchers.
   * 
   * @return Organization's affiliated researchers.
   */
  public String getAffiliatedResearcher() {
    return this.affiliatedResearcher;
  }

  /**
   * Provides the Organization's country.
   * 
   * @return The organization's country
   */
  public String getCountry() {
    return this.country;
  }

  /**
   * Provides the Organization's research keywords.
   * @return Organization's research keyword.
   */
  public String getResearchKeywords() {
    return this.researchKeywords;
  }

  /**
   * Provides the Organization's research description.
   * @return Organization's research description.
   */
  public String getResearchDescription() {
    return this.researchDescription;
  }

  /**
   * Provides the Organization's home page.
   * @return Organization's home page.
   */
  public String getHomePage() {
    return this.homePage;
  }

  /**
   * Sets the Organization's name.
   * @param organizationName  The new organization name
   */
  public void setOrganizationName(String organizationName) {
    this.organizationName = organizationName;
  }

  /**
   * Sets the Organization type.
   * @param organizationType The new organization type
   */
  public void setOrganizationType(String organizationType) {
    this.organizationType = organizationType;
  }

  /**
   * Sets the organization's contact.
   * @param contact The new contact
   */
  public void setContact(String contact) {
    this.contact = contact;
  }

  /**
   * Sets the organization's affiliated researchers.
   * @param affiliatedResearcher The new affiliated researcher
   */
  public void setAffiliatedResearcher(String affiliatedResearcher) {
    this.affiliatedResearcher = affiliatedResearcher;
  }

  /**
   * Sets the Organization's country.
   * @param country The new country
   */
  public void setCountry(String country) {
    this.country = country;
  }

  /**
   * Sets the Organization's keywords.
   * @param researchKeywords The new research keywords
   */
  public void setResearchKeywords(String researchKeywords) {
    this.researchKeywords = researchKeywords;
  }

  /**
   * Sets the organization's research description.
   * @param researchDescription The new research description
   */
  public void setResearchDescription(String researchDescription) {
    this.researchDescription = researchDescription;
  }

  /**
   * Sets the Organization's home page.
   * @param homePage The new home page
   */
  public void setHomePage(String homePage) {
    this.homePage = homePage;
  }

  /**
   * A handler that performs the action when the 'save' button is pressed.
   * Saves the new Researcher.
   * @return A Resolution indicating to redisplay the mainPage.jsp page.
   * @throws Exception If an error occurs.
   */
  public Resolution saveResearcher() throws Exception {
    boolean isValid = true;
    if (this.getResearcherName() == null) {
      this.errorMessage = nameEmpty;
      isValid = false;
    }
    else if (this.getResearcherOrganization() == null) {
      this.errorMessage = "Organization field cannot be empty!";
      isValid = false;
    }
    else if (this.getEmail() == null) {
      this.errorMessage = "Email field cannot be empty!";
      isValid = false;
    }
    
    if (isValid) {
      myIsernModel.saveResearcher(this.getResearcherName(), this
        .getResearcherOrganization(), this.getEmail(), this.getPictureLink(),
        this.getBioStatement());
      String success = "";
      return new StreamingResolution(text, new StringReader(success));
    }
    else {
      String error = this.errorMessage;
      return new StreamingResolution(text, new StringReader(error));
    }
  }

  /**
   * Provides the Researcher's name.
   * @return Researcher's name.
   */
  public String getResearcherName() {
    return this.researcherName;
  }

  /**
   * Provides the Researcher's organization.
   * @return Researcher's organization.
   */
  public String getResearcherOrganization() {
    return this.researcherOrganization;
  }

  /**
   * Provides the Researcher's email.
   * @return Researcher's email.
   */
  public String getEmail() {
    return this.email;
  }

  /**
   * Provides the Researcher's picture link.
   * @return Researcher's picture link.
   */
  public String getPictureLink() {
    return this.pictureLink;
  }

  /**
   * Provides the Researcher's bio statement.
   * @return Researcher's bio statement.
   */
  public String getBioStatement() {
    return this.bioStatement;
  }

  /**
   * Sets the Researcher's Name.
   * @param researcherName New researcher's name
   */
  public void setResearcherName(String researcherName) {
    this.researcherName = researcherName;
  }

  /**
   * Sets the Researcher's Oragnization.
   * @param researcherOrganization The new research organization
   */
  public void setResearcherOrganization(String researcherOrganization) {
    this.researcherOrganization = researcherOrganization;
  }

  /**
   * Sets the Researcher's email.
   * @param email The new email
   */
  public void setEmail(String email) {
    this.email = email;
  }

  /**
   * Sets the Researcher's picture link.
   * @param pictureLink The new picture link.
   */
  public void setPictureLink(String pictureLink) {
    this.pictureLink = pictureLink;
  }

  /**
   * Sets the researcher's bio statement.
   * @param bioStatement The new bio statement.
   */
  public void setBioStatement(String bioStatement) {
    this.bioStatement = bioStatement;
  }

  /**
   * Provides the Myisern password.
   * @return Myisern password.
   */
  public String getPassword() {
    return this.password;
  }

  /**
   * Sets the Myisern password.
   * @param password The login password
   */
  public void setPassword(String password) {
    this.password = password;
  }

  /**
   * Returns the error message, which may be empty. Indicates if someone tried
   * to pop an empty stack.
   * 
   * @return The error message.
   */
  public String getErrorMessage() {
    return this.errorMessage;
  }

  /**
   * A handler that performs the action when the 'push' button is pressed.
   * Performs a sanity check.
   * @return A Resolution indicating to redisplay the index.jsp page.
   *
   */
  public Resolution checkSanity() {
    return new ForwardResolution("/sanityCheckReprort.jsp");
  }

  /**
   * Gets the system time.
   * 
   * @return the current time.
   */
  public String getTime() {
    Calendar now = Calendar.getInstance();
    Format fullUSDate = DateFormat.getDateInstance(DateFormat.FULL, Locale.US);
    // SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd
    // HH:mm:ss");

    return fullUSDate.format(now.getTime());
  }
  /**
   * Researcher filter flag.
   * @return True/False
   */
  public boolean getCheckResearchers() {
    return this.checkResearchers;
  }
  /**
   * Organization filter flag.
   * @return True/False
   */
  public boolean getCheckOrganizations() {
    return this.checkOrganizations;
  }
  /**
   * Collaboration filter flag.
   * @return True/False
   */
  public boolean getCheckCollaborations() {
    return this.checkCollaborations;
  }
  /**
   * Displays the Sanity Check Report Page.
   * @return ForwardResolution to redisplay the scReport.jsp page
   */
  public Resolution sanityCheckReport() {
    return new ForwardResolution("/scReport.jsp");
  }
  /**
   * Updates the Sanity Check Report page with filter applied.
   * @return ForwardResolution to redisplay the scReport.jsp page
   */
  public Resolution filterReport() {
    return new ForwardResolution("/scReport.jsp");
  }
  /**
   * Returns Filter string.
   * @return filter string.
   */
  public String getFilterSetting() {
    return this.filter;
  }
  /**
   * Applies filtering for report.
   * @param filter Filter setting.
   */
  public void setFilterSetting(String filter) {
    this.filter = filter;
    if ("researchers".equals(filter)) {
      this.checkCollaborations = false;
      this.checkOrganizations = false;
      this.checkResearchers = true;
    }
    else if ("organizations".equals(filter)) {
      this.checkCollaborations = false;
      this.checkResearchers = false;
      this.checkOrganizations = true;
    }
    else if ("collaborations".equals(filter)) {
      this.checkOrganizations = false;
      this.checkResearchers = false;
      this.checkCollaborations = true;
    }
    else if ("all".equals(filter)) {
      this.checkCollaborations = true;
      this.checkOrganizations = true;
      this.checkResearchers = true;
    }
  }
  /**
   * Gets the list of errors.
   * 
   * @return The report iterator.
   * 
   */
  public Iterator<SanityCheckErrorItem> getReportIterator() {
    try {
      return myIsernModel.getReportIterator();
    }
    catch (Exception e) {
      return null;
    }
  }

  /**
   * Provides a List of researchers.
   * 
   * @return List of researchers.
   */
  public List<Researcher> getResearchers() {
    return this.researchers;
  }

  /**
   * Provides a List of collaborations.
   * 
   * @return List of collaborations.
   */
  public List<Collaboration> getCollaborations() {
    return this.collaborations;
  }

  /**
   * Provides a List of organizations.
   * 
   * @return List of organizations.
   */
  public List<Organization> getOrganizations() {
    return this.organizations;
  }

  /**
   * Provides a collection of Researchers to the displayResearchers page
   * 
   * @return The stack iterator.
   * @throws Exception  If an error occurs.
   */
  public Resolution displayResearchers() throws Exception {
    this.researchers = myIsernModel.getResearcher();
    return new ForwardResolution("/displayResearchers.jsp");
  }

  /**
   * Provides a collection of collaborations to the displayCollaborations page.
   * 
   * @return The collaborations.
   * @throws Exception  If an error occurs.
   */
  public Resolution displayCollaborations() throws Exception {
    this.collaborations = myIsernModel.getCollaboration();
    return new ForwardResolution("/displayCollaborations.jsp");
  }

  /**
   * Provides a collection of Organizations to the displayOrganizations page.
   * 
   * @return The organizations.
   * @throws Exception If an error occurs.
   */
  public Resolution displayOrganizations() throws Exception {
    this.organizations = myIsernModel.getOrganization();
    return new ForwardResolution("/displayOrganizations.jsp");
  }
  
  /**
   * Finds the unique id.
   * @return unique id if exists
   */
  public String getFindId() {
    return this.findId;
  }
  
  /**
   * Sets the unique id.
   * @param findId the unique id
   */
  public void setFindId(String findId) {
    this.findId = findId;
  }
  
  /**
   * Finds the unique researcher object.
   * @return resolution
   * @throws Exception if error occur
   */
  public Resolution findResearcher() throws Exception {
    this.editResearcher = new Researcher();
    if (this.findId == null) {
      this.errorMessage = "Name field cannot be empty";
      return new StreamingResolution(text, new StringReader(this.errorMessage));
    }
    else {
      String result = myIsernModel.findResearcher(this.findId);
      if (result == "") {
        result = "Add Researcher";
        return new StreamingResolution(text, new StringReader(result));
      }
      else {
        int count = 0;
        String uniqueId = result.replace('_', ' ');
         for (Researcher each : MyIsernModel.getInstance().getResearcher()) {
           if (each.getName().toString().trim().equals(uniqueId)) {
             this.editResearcher = each;
             myIsernModel.index = count;
           }
           count++;
         }
         this.researcherName = this.editResearcher.getName();
         this.researcherOrganization = this.editResearcher.getOrganization();
         this.email = this.editResearcher.getEmail();
         this.pictureLink = this.editResearcher.getPictureLink();
         this.bioStatement = this.editResearcher.getBioStatement();
         result = "Edit Researcher";
         return new ForwardResolution("/editResearcher.jsp");   
      }
    }
  }
  /**
   * Saves the newly edited Researcher object.
   * @return resolution
   * @throws Exception if error occur
   */
  public Resolution saveEditedResearcher() throws Exception {
   boolean isValid = true;
   if (this.getResearcherName() == null) {
     this.errorMessage = nameEmpty;
     isValid = false;
   }
   else if (this.getResearcherOrganization() == null) {
     this.errorMessage = "Organization field cannot be empty!";
     isValid = false;
   }
   else if (this.getEmail() == null) {
     this.errorMessage = "Email field cannot be empty!";
     isValid = false;
   }
   
   if (isValid) {
     this.editResearcher = new Researcher();
     this.editResearcher.setName(this.getResearcherName()); 
     
     this.editResearcher.setEmail(this.getEmail());
     this.editResearcher.setOrganization(this.getResearcherOrganization());
     this.editResearcher.setPictureLink(this.getPictureLink());
     this.editResearcher.setBioStatement(this.getBioStatement());
     
     myIsernModel.saveEditedResearcher(editResearcher);
     String success = "";
     return new StreamingResolution(text, new StringReader(success));
   }
   else {
     String error = this.errorMessage;
     return new StreamingResolution(text, new StringReader(error));
   }
  }
  
  /** 
   * Finds name of a unique organization.
   * @return resolution
   */
  public Resolution findOrganization() {
    if (this.findId == null) {
      this.errorMessage = "Name field cannot be empty";
      return new StreamingResolution(text, new StringReader(this.errorMessage));
    }
    else {
      String result = myIsernModel.findOrganization(this.findId);
      if (result == "") {
        result = "Add Organization";
        return new StreamingResolution(text, new StringReader(result));
      }
      else {
        result = "Edit Organization";
        return new StreamingResolution(text, new StringReader(result));
      }
    }
  }
  
  /**
   * Finds the collaboration unique name.
   * @return resolution
   */
  public Resolution findCollaboration() {
    if (this.findId == null) {
      this.errorMessage = "Name field cannot be empty";
      return new StreamingResolution(text, new StringReader(this.errorMessage));
    }
    else {
      String result = myIsernModel.findCollaboration(this.findId);
      if (result == "") {
        result = "Add Collaboration";
        return new StreamingResolution(text, new StringReader(result));
      }
      else {
        result = "Edit Collaboration";
        return new StreamingResolution(text, new StringReader(result));
      }
    }
  }
}

